package com.websocket.service.mapping;

import com.websocket.MessageData;
import com.websocket.annotation.WsController;
import com.websocket.annotation.WsMapping;
import com.websocket.hander.HandlerExecutionChain;
import com.websocket.hander.HandlerInterceptor;
import com.websocket.hander.InterceptorRegistry;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class WebSocketHandlerMapping {

    private final Map<String, HandlerExecution> handlers = new ConcurrentHashMap<>();

    public WebSocketHandlerMapping(ApplicationContext applicationContext, InterceptorRegistry interceptorRegistry) {
        // 获取所有被 WsController 注解的 bean
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(WsController.class);
        // 注册 handlers
        registryHandlers(controllers, interceptorRegistry);
    }

    private void registryHandlers(Map<String, Object> controllers, InterceptorRegistry interceptorRegistry) {
        controllers.forEach((name, bean) -> {
            Class<?> cls = bean.getClass();
            WsMapping classWsMapping = cls.getAnnotation(WsMapping.class);
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods) {
                // 跳过静态方法
                if (Modifier.isStatic(method.getModifiers())) continue;

                // 跳过没有 WsMapping 注解的方法
                WsMapping methodWsMapping = method.getAnnotation(WsMapping.class);
                if (methodWsMapping == null) continue;

                String handlerName = classWsMapping == null
                        ? methodWsMapping.value()
                        : classWsMapping.value() + methodWsMapping.value();

                // handlerName 已存在
                if (handlers.containsKey(handlerName)) {
                    throw new BeanCreationException("Error creating HandlerMapping for WebSocket. " +
                            "Cannot map method " + method + " to '" + handlerName + "': " +
                            "There is already method " + handlers.get(handlerName) + " mapped");
                }
                HandlerMethod handlerMethod = new HandlerMethod(method, bean);
                List<HandlerInterceptor> interceptors = interceptorRegistry.getInterceptors(handlerName);

                handlers.put(handlerName, new HandlerExecution(handlerMethod, new HandlerExecutionChain(interceptors)));
            }
        });
    }

    public HandlerExecution getHandler(MessageData message) {
        return handlers.get(message.getPath());
    }

}
